package com.gxa.common.utils;

import com.gxa.common.exception.ResultException;
import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.temporal.TemporalAdjusters;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 日期处理
 */
public class DateUtils {
    /**
     * 时间格式(yyyy-MM-dd)
     */
    public final static String DATE_PATTERN = "yyyy-MM-dd";
    /**
     * 时间格式(yyyy-MM-dd HH:mm:ss)
     */
    public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     *
     * @param date 日期
     * @return 返回yyyy-MM-dd格式日期
     */
    public static String format(Date date) {
        return format(date, DATE_PATTERN);
    }

    /**
     * 日期格式化 日期格式为：yyyy-MM-dd
     *
     * @param date    日期
     * @param pattern 格式，如：DateUtils.DATE_TIME_PATTERN
     * @return 返回yyyy-MM-dd格式日期
     */
    public static String format(Date date, String pattern) {
        if (date != null) {
            SimpleDateFormat df = new SimpleDateFormat(pattern);
            return df.format(date);
        }
        return null;
    }


    /**
     * 字符串转换成日期
     *
     * @param strDate 日期字符串
     * @param pattern 日期的格式，如：DateUtils.DATE_TIME_PATTERN
     */
    public static Date stringToDate(String strDate, String pattern) {
        if (StringUtils.isBlank(strDate)) {
            return null;
        }

        DateTimeFormatter fmt = DateTimeFormat.forPattern(pattern);
        return fmt.parseLocalDateTime(strDate).toDate();
    }

    /**
     * 根据周数，获取开始日期、结束日期
     *
     * @param week 周期  0本周，-1上周，-2上上周，1下周，2下下周
     * @return 返回date[0]开始日期、date[1]结束日期
     */
    public static Date[] getWeekStartAndEnd(int week) {
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusWeeks(week));

        date = date.dayOfWeek().withMinimumValue();
        Date beginDate = date.toDate();
        Date endDate = date.plusDays(6).toDate();
        return new Date[]{beginDate, endDate};
    }

    /**
     * 根据周数，一周全部日期
     *
     * @param week 周期  0本周，-1上周，-2上上周，1下周，2下下周
     * @return 返回date[0]开始日期、date[1]结束日期
     */
    public static Date[] getWeekDays(int week) {
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusWeeks(week));

        date = date.dayOfWeek().withMinimumValue();
        Date date1 = date.toDate();
        Date date2 = date.plusDays(1).toDate();
        Date date3 = date.plusDays(2).toDate();
        Date date4 = date.plusDays(3).toDate();
        Date date5 = date.plusDays(4).toDate();
        Date date6 = date.plusDays(5).toDate();
        Date date7 = date.plusDays(6).toDate();
        return new Date[]{date1, date2, date3, date4, date5, date6, date7};
    }

    /**
     * 根据周数，一周全部日期 字符串
     *
     * @param week 周期  0本周，-1上周，-2上上周，1下周，2下下周
     * @return 返回date[0]开始日期、date[1]结束日期
     */
    public static List<String> getStringWeekDays(int week) {
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime.plusWeeks(week));

        date = date.dayOfWeek().withMinimumValue();
        String date1 = DateUtils.format(date.toDate(), "yyyy-MM-dd");
        String date2 = DateUtils.format(date.plusDays(1).toDate(), "yyyy-MM-dd");
        String date3 = DateUtils.format(date.plusDays(2).toDate(), "yyyy-MM-dd");
        String date4 = DateUtils.format(date.plusDays(3).toDate(), "yyyy-MM-dd");
        String date5 = DateUtils.format(date.plusDays(4).toDate(), "yyyy-MM-dd");
        String date6 = DateUtils.format(date.plusDays(5).toDate(), "yyyy-MM-dd");
        String date7 = DateUtils.format(date.plusDays(6).toDate(), "yyyy-MM-dd");
        List<String> days = new ArrayList<>();
        days.add(date1);
        days.add(date2);
        days.add(date3);
        days.add(date4);
        days.add(date5);
        days.add(date6);
        days.add(date7);
        return days;
    }

    /**
     * 获取本地当天 日期字符串
     *
     * @return
     */
    public static String getStringToday() {
        DateTime dateTime = new DateTime();
        LocalDate date = new LocalDate(dateTime);
        return format(date.toDate(), "yyyy-MM-dd");
    }

    /**
     * 计算两个日期之间相差的天数
     *
     * @param date1 较小的时间
     * @param date2 较大的时间
     * @return 相差天数
     * calendar 对日期进行时间操作
     * getTimeInMillis() 获取日期的毫秒显示形式
     */
    public static int getDaysBetween(Date date1, Date date2) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date1);
        long time1 = cal.getTimeInMillis();
        cal.setTime(date2);
        long time2 = cal.getTimeInMillis();
        long between_days = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(between_days));
    }

    /**
     * 计算两个字符串日期之间相差的天数
     *
     * @param smalldate 较小的日期
     * @param bigDate   较大的日期
     * @return
     */
    public static int getDaysBetween(String smalldate, String bigDate) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        try {
            cal.setTime(sdf.parse(smalldate));
        } catch (ParseException e) {
            e.printStackTrace();
            throw new ResultException("日期解析错了");
        }
        long time1 = cal.getTimeInMillis();
        try {
            cal.setTime(sdf.parse(bigDate));
        } catch (ParseException e) {
            e.printStackTrace();
            throw new ResultException("日期解析错了");
        }
        long time2 = cal.getTimeInMillis();
        long between_days = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(between_days));
    }

    /**
     * 字符串日期格式和date日期格式的计算
     *
     * @param date1
     * @param date2
     * @return
     * @throws ParseException
     */
    public static int getDaysBetween(String date1, Date date2) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        try {
            cal.setTime(sdf.parse(date1));
        } catch (ParseException e) {
            e.printStackTrace();
            throw new ResultException(e.getMessage() + "-----" + "解析出错误了");
        }
        long time1 = cal.getTimeInMillis();
        cal.setTime(date2);
        long time2 = cal.getTimeInMillis();
        long between_days = (time2 - time1) / (1000 * 3600 * 24);
        return Integer.parseInt(String.valueOf(between_days));
    }

    /**
     * 获取某天的是星期几的字符串
     *
     * @param date
     * @return
     */
    public static String getDayWithWeekString(Date date) {
        String[] week = {"周日", "周一", "周二", "周三", "周四", "周五", "周六"};
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int weekIndex = cal.get(Calendar.DAY_OF_WEEK) - 1;
        if (weekIndex < 0) {
            weekIndex = 0;
        }
        return week[weekIndex];
    }

    /**
     * 对日期的【秒】进行加/减
     *
     * @param date    日期
     * @param seconds 秒数，负数为减
     * @return 加/减几秒后的日期
     */
    public static Date addDateSeconds(Date date, int seconds) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusSeconds(seconds).toDate();
    }

    /**
     * 对日期的【分钟】进行加/减
     *
     * @param date    日期
     * @param minutes 分钟数，负数为减
     * @return 加/减几分钟后的日期
     */
    public static Date addDateMinutes(Date date, int minutes) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMinutes(minutes).toDate();
    }

    /**
     * 对日期的【小时】进行加/减
     *
     * @param date  日期
     * @param hours 小时数，负数为减
     * @return 加/减几小时后的日期
     */
    public static Date addDateHours(Date date, int hours) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusHours(hours).toDate();
    }

    /**
     * 对日期的【天】进行加/减
     *
     * @param date 日期
     * @param days 天数，负数为减
     * @return 加/减几天后的日期
     */
    public static Date addDateDays(Date date, int days) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusDays(days).toDate();
    }

    /**
     * 对日期的【周】进行加/减
     *
     * @param date  日期
     * @param weeks 周数，负数为减
     * @return 加/减几周后的日期
     */
    public static Date addDateWeeks(Date date, int weeks) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusWeeks(weeks).toDate();
    }

    /**
     * 对日期的【月】进行加/减
     *
     * @param date   日期
     * @param months 月数，负数为减
     * @return 加/减几月后的日期
     */
    public static Date addDateMonths(Date date, int months) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusMonths(months).toDate();
    }

    /**
     * 对日期的【年】进行加/减
     *
     * @param date  日期
     * @param years 年数，负数为减
     * @return 加/减几年后的日期
     */
    public static Date addDateYears(Date date, int years) {
        DateTime dateTime = new DateTime(date);
        return dateTime.plusYears(years).toDate();
    }

    /**
     * 比较两日期之间的大小 时间比较时间戳的方式
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean CompareDate(Date date1, Date date2) {
        return date1.getTime() > date2.getTime();
    }

    /**
     * 比较两日期之间的大小 时间比较时间戳的方式
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean CompareDate(String date1, String date2) {
        return stringToDate(date1, "yyyy-MM-dd").getTime() > stringToDate(date2, "yyyy-MM-dd").getTime();
    }

    /**
     * 比较两日期之间的大小 时间比较时间戳的方式
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean CompareDate(String date1, Date date2) {
        return stringToDate(date1, "yyyy-MM-dd").getTime() > date2.getTime();
    }


    /**
     * 通过生日日期计算年龄（周岁算法）：用当年年份-生日年份，若若生日的月份和日数 > 当年的月份和日数，则减1
     *
     * @param birDate 生日日期
     * @return int年龄
     */
    public static int getAgeByBirDate(Date birDate) {
        int age = 0;
        try {
            if (birDate.after(new Date())) {
                return 0;
            }

            Calendar now = Calendar.getInstance();
            now.setTime(new Date());// 当前时间

            Calendar birth = Calendar.getInstance();
            birth.setTime(birDate);// 生日日期

            // 年龄为虚岁，用当年年份-生日年份
            age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR);

            birth.set(Calendar.YEAR, now.get(Calendar.YEAR));
            now.set(Calendar.HOUR_OF_DAY, birth.get(Calendar.HOUR_OF_DAY));
            now.set(Calendar.MINUTE, birth.get(Calendar.MINUTE));
            now.set(Calendar.SECOND, birth.get(Calendar.SECOND));
            now.set(Calendar.MILLISECOND, birth.get(Calendar.MILLISECOND));
            if (birth.after(now)) {// 若生日的月份和日数 > 当年的月份和日数，则减1
                age--;
            }
            return age;
        } catch (Exception e) {// 兼容性更强,异常后返回数据
            return 0;
        }
    }

    /**
     * 通过年龄计算生日日期（周岁算法）：年份减去年龄，默认当前的月份和日数，为生日日期的月份和日数
     *
     * @param age 年龄
     * @return Date 生日日期
     */
    public static Date getBirDateByAge(Integer age) {
        Date birDate = new Date();
        try {
            Calendar now = Calendar.getInstance();
            now.setTime(new Date());// 当前时间

            // 通过年龄计算生日日期，年份减去年龄，默认当前的月份和日数 为生日日期的月份和日数
            now.add(Calendar.YEAR, 0 - age);
            birDate = now.getTime();
            return birDate;
        } catch (Exception e) {// 兼容性更强,异常后返回数据
            return null;
        }
    }

    /**
     * 获取下一天
     *
     * @param date
     * @return
     */
    public static Date getNextDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        cal.add(Calendar.DAY_OF_MONTH, 1);
        return cal.getTime();
    }

    /**
     * 获得 指定日期 后几天  只支持一个月内 和 支持跨两个月使用（本月下个月）（你可以用递归 升级到 任意天数 跨多个月）
     * 对我目前的需求来说以满足我的要求==> TODO待升级
     * @param specifiedDay 指定日期
     * @param num 后面几天
     * @return
     * @author zhuiyi
     */
    public static List<String> getDayAndAfterNumDays(String specifiedDay, Integer num) {
        String format = "yyyy-MM-dd";
        Calendar c = Calendar.getInstance();
        Date date = null;
        List<String> dayList = new ArrayList<>();
        //        //获取当月最后一天
        String lastDay = getLastDayByMonth(specifiedDay);
        int daysBetween = getDaysBetween(specifiedDay, lastDay);
        if (daysBetween >= num) {
            try {
                // date = new SimpleDateFormat("yy-MM-dd").parse(specifiedDay);
                date = new SimpleDateFormat(format).parse(specifiedDay);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            c.setTime(date);
            int day = c.get(Calendar.DATE);
            for (int i = 0; i < num; i++) {
                c.set(Calendar.DATE, day + i);
                String dayAfter = new SimpleDateFormat(format).format(c.getTime());
                dayList.add(dayAfter);
            }

            return dayList;
        } else { //到下个月了
            //本月的正常生成
            try {
                date = new SimpleDateFormat(format).parse(specifiedDay);
            } catch (ParseException e) {
                e.printStackTrace();
            }
            c.setTime(date);
            int day = c.get(Calendar.DATE);
            for (int i = 0; i < daysBetween + 1; i++) {
                c.set(Calendar.DATE, day + i);
                String dayAfter = new SimpleDateFormat(format).format(c.getTime());
                dayList.add(dayAfter);
            }
            //下个月的
            //获取下个月第一天
            Date nextMonthFirstDay = getNextDate(stringToDate(lastDay, "yyyy-MM-dd"));
            date = nextMonthFirstDay;

            c.setTime(date);
            day = c.get(Calendar.DATE);
            for (int j = 0; j < num - (daysBetween + 1); j++) {
                c.set(Calendar.DATE, day + j);
                String dayAfter = new SimpleDateFormat(format).format(c.getTime());
                dayList.add(dayAfter);
            }
            return dayList;
        }

    }


    /**
     * 根据给的时间获取此月的最后一天
     * 传入参数为String，可传入：1、"201807"；2、"2018-07-01"
     *
     * @param date 账期
     * @return String
     * 当月的最后一天
     */
    public static String getLastDayByMonth(String date) {
        if (date.contains("-")) {
            date = date.replaceAll("-", "");
        } else if (date.length() < 6 || date.length() > 10) {
            System.out.println("日期错误！");
        }
        int year = Integer.parseInt(date.substring(0, 4));
        int month = Integer.parseInt(date.substring(4, 6));
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month - 1);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        return new SimpleDateFormat("yyyy-MM-dd").format(cal.getTime());
    }

    /**
     * 根据给的时间获取此月的第一天
     * 传入参数为String，可传入：1、"201807"；2、"2018-07-01"
     *
     * @param date 账期
     * @return String
     * 当月的第一天
     */
    public static String getFirstDayByMonth(String date) {
        if (date.contains("-")) {
            date = date.replaceAll("-", "");
        } else if (date.length() < 6 || date.length() > 10) {
            System.out.println("日期错误！");
        }
        int year = Integer.parseInt(date.substring(0, 4));
        int month = Integer.parseInt(date.substring(4, 6));
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.YEAR, year);
        cal.set(Calendar.MONTH, month - 1);
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.DATE));
        return new SimpleDateFormat("yyyy-MM-dd ").format(cal.getTime());
    }


}
 
